package com.tlgen.orm.utils.xml;

import com.tlgen.orm.utils.orm.IdWorker;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class EnhancedSqlProcessor {

    @Data
    public static class SqlStatement {
        private final String id;
        private final String rawContent;
        private final List<SqlParamInfo> paramInfos;
        private final List<DynamicTagInfo> tagInfos;

        public SqlStatement(String id, String rawContent,
                            List<SqlParamInfo> paramInfos,
                            List<DynamicTagInfo> tagInfos) {
            this.id = id;
            this.rawContent = rawContent;
            this.paramInfos = paramInfos;
            this.tagInfos = tagInfos;
        }

        /**
         * 渲染SQL语句
         *
         * @param params 完整的参数映射
         * @return 渲染后的SQL
         */
        public String render(Map<String, Object> params) {
            StringBuilder sb = new StringBuilder(rawContent);

            // 先处理动态标签（从内向外）
            List<DynamicTagInfo> reversedTags = new ArrayList<>(tagInfos);
            Collections.reverse(reversedTags);

            for (DynamicTagInfo tag : reversedTags) {
                String replacement = renderTag(tag, params);
                sb.replace(tag.getStartIndex(), tag.getEndIndex(), replacement);
            }

            // 处理普通参数
            for (SqlParamInfo param : paramInfos) {
                String paramValue = getParamValue(param, params);
                String placeholder = "#{" + param.getFullExpression() + "}";
                int index = sb.indexOf(placeholder);
                while (index != -1) {
                    sb.replace(index, index + placeholder.length(), paramValue);
                    index = sb.indexOf(placeholder, index + paramValue.length());
                }
            }

            return sb.toString();
        }

        private String renderTag(DynamicTagInfo tag, Map<String, Object> params) {
            switch (tag.getType()) {
                case FOREACH:
                    return renderForeachTag(tag, params);
                case IF:
                    return renderIfTag(tag, params);
                // 其他标签类型...
                default:
                    return "";
            }
        }

        private String renderForeachTag(DynamicTagInfo tag, Map<String, Object> params) {
            // 获取标签属性
            Map<String, String> attributes = tag.getAttributes();
            String collectionKey = attributes.get("collection");
            if (collectionKey == null || collectionKey.isEmpty()) {
                return "";
            }

            // 获取集合参数值
            Object collectionValue = params.get(collectionKey);
            if (collectionValue == null) {
                return "";
            }

            // 转换为列表形式
            List<?> items = toList(collectionValue);
            if (items.isEmpty()) {
                return "";
            }

            StringBuilder sb = new StringBuilder();

            // 获取分隔符和开闭标记
            String open = attributes.getOrDefault("open", "");
            String close = attributes.getOrDefault("close", "");
            String separator = attributes.getOrDefault("separator", ",");

            // 获取item属性（循环变量名）
            String itemName = attributes.get("item");
            if (itemName == null || itemName.isEmpty()) {
                itemName = "item";
            }

            // 处理所有元素
            for (int i = 0; i < items.size(); i++) {
                if (i > 0) sb.append(separator);

                Object item = items.get(i);

                // 创建子参数上下文
                Map<String, Object> itemParams = new HashMap<>(params);

                // 关键：直接放入整个对象（而不是值）
                itemParams.put(itemName, item);

                // 渲染内容（正确处理 #{user.username} 表达式）
                String renderedContent = renderContent(tag.getContent(), itemParams);
                sb.append(renderedContent);
            }

            return open + sb + close;
        }

        // 修复 NULL 处理
        private String getParamValue(SqlParamInfo param, Map<String, Object> params) {
            Object value = params.get(param.getName());
            if (value == null) {
                return "NULL"; // 直接返回 NULL 字符串
            }

            // 处理嵌套属性（如 user.username）
            if (param.hasExpressionChain()) {
                for (String prop : param.getExpressionChain().subList(1, param.getExpressionChain().size())) {
                    value = getPropertyValue(value, prop);
                    if (value == null) return "NULL";
                }
            }

            // 格式化值（自动添加单引号）
            return formatSqlValue(value);
        }

        // 简化值格式化方法
        private String formatSqlValue(Object value) {
            if (value == null) {
                return "NULL";
            }

            String stringValue = value.toString();

            // 数字不加引号
            if (isNumeric(stringValue)) {
                return stringValue;
            }

            // 布尔不加引号
            if ("true".equalsIgnoreCase(stringValue) || "false".equalsIgnoreCase(stringValue)) {
                return stringValue;
            }

            // 其他情况添加单引号
            return "'" + sanitizeSqlValue(stringValue) + "'";
        }

        private Object getPropertyValue(Object obj, String property) {
            if (obj == null) return null;

            if (obj instanceof Map) {
                return ((Map<?, ?>) obj).get(property);
            }

            // 尝试反射获取属性值
            try {
                // 尝试getter方法
                String getterName = "get" + property.substring(0, 1).toUpperCase() + property.substring(1);
                Method getter = obj.getClass().getMethod(getterName);
                return getter.invoke(obj);
            } catch (Exception ex) {
                // 如果getter方法不存在，尝试字段
                try {
                    Field field = obj.getClass().getDeclaredField(property);
                    field.setAccessible(true);
                    return field.get(obj);
                } catch (Exception e) {
                    return null;
                }
            }
        }

        // 支持多种集合类型的转换（返回List）
        private List<?> toList(Object collection) {
            if (collection == null) {
                return Collections.emptyList();
            }

            if (collection instanceof List) {
                return (List<?>) collection;
            }

            if (collection.getClass().isArray()) {
                return Arrays.asList((Object[]) collection);
            }

            if (collection instanceof Collection) {
                return new ArrayList<>((Collection<?>) collection);
            }

            if (collection instanceof Map) {
                return new ArrayList<>(((Map<?, ?>) collection).values());
            }

            return Collections.singletonList(collection);
        }

        // 增强的内容渲染方法
        private String renderContent(String content, Map<String, Object> params) {
            // 创建临时SQL语句
            SqlStatement temp = new SqlStatement("temp_" + IdWorker.nextId(), content,
                    extractParamInfos(content),
                    extractTagInfos(content));
            // 渲染内容
            return temp.render(params);
        }

        // 检查是否是数字类型
        private boolean isNumeric(String value) {
            try {
                Double.parseDouble(value);
                return true;
            } catch (NumberFormatException e) {
                return false;
            }
        }

        private String renderIfTag(DynamicTagInfo tag, Map<String, Object> params) {
            // 评估测试表达式
            if (evaluateExpression(tag.getTest(), params)) {
                return renderContent(tag.getContent(), params);
            }
            return "";
        }

    }

    public static class SqlParamInfo {
        private final String fullExpression;
        private final List<String> expressionChain;
        private final String jdbcType;

        public SqlParamInfo(String fullExpression, String jdbcType) {
            this.fullExpression = fullExpression;
            this.expressionChain = parseExpressionChain(fullExpression);
            this.jdbcType = jdbcType;
        }

        private List<String> parseExpressionChain(String expr) {
            return Arrays.stream(expr.split("\\."))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .collect(Collectors.toList());
        }

        // Getters
        public String getFullExpression() {
            return fullExpression;
        }

        public List<String> getExpressionChain() {
            return expressionChain;
        }

        public String getName() {
            return expressionChain.get(0);
        }

        public boolean hasExpressionChain() {
            return expressionChain.size() > 1;
        }

        public String getJdbcType() {
            return jdbcType;
        }
    }

    public enum TagType {
        IF, FOREACH, CHOOSE, WHEN, OTHERWISE, WHERE, SET, TRIM
    }

    public static class DynamicTagInfo {
        private final TagType type;
        private final int startIndex;
        private final int endIndex;
        private final String content;
        private final Map<String, String> attributes;

        public DynamicTagInfo(TagType type, int startIndex, int endIndex,
                              String content, Map<String, String> attributes) {
            this.type = type;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.content = content;
            this.attributes = attributes;
        }

        // Getters
        public TagType getType() {
            return type;
        }

        public int getStartIndex() {
            return startIndex;
        }

        public int getEndIndex() {
            return endIndex;
        }

        public String getContent() {
            return content;
        }

        // 添加 getAttributes() 方法
        public Map<String, String> getAttributes() {
            return attributes;
        }

        // 特定标签的快捷方法
        public String getTest() {
            return getAttribute("test");
        }

        public String getCollection() {
            return getAttribute("collection");
        }

        public String getItem() {
            return getAttribute("item");
        }

        public String getOpen() {
            return getAttribute("open");
        }

        public String getClose() {
            return getAttribute("close");
        }

        public String getSeparator() {
            return getAttribute("separator");
        }

        // 辅助方法：获取属性值，如果不存在返回默认值
        public String getAttribute(String name, String defaultValue) {
            return attributes.getOrDefault(name, defaultValue);
        }

        // 辅助方法：获取属性值
        public String getAttribute(String name) {
            return attributes.get(name);
        }
    }

    // ==================== 解析方法 ====================

    public static SqlStatement parseSqlStatement(String id, String sqlContent) {
        List<SqlParamInfo> paramInfos = extractParamInfos(sqlContent);
        List<DynamicTagInfo> tagInfos = extractTagInfos(sqlContent);
        return new SqlStatement(id, sqlContent, paramInfos, tagInfos);
    }

    private static List<SqlParamInfo> extractParamInfos(String sqlContent) {
        List<SqlParamInfo> params = new ArrayList<>();
        Matcher matcher = Pattern.compile("#\\{(.*?)}").matcher(sqlContent);

        while (matcher.find()) {
            String expr = matcher.group(1).trim();
            String[] parts = expr.split(",");

            String fullExpr = parts[0].trim();
            String jdbcType = null;

            for (int i = 1; i < parts.length; i++) {
                if (parts[i].trim().startsWith("jdbcType=")) {
                    jdbcType = parts[i].split("=")[1].trim();
                }
            }

            params.add(new SqlParamInfo(fullExpr, jdbcType));
        }
        return params;
    }

    private static List<DynamicTagInfo> extractTagInfos(String sqlContent) {
        List<DynamicTagInfo> tags = new ArrayList<>();
        Matcher matcher = Pattern.compile("<(\\w+)([^>]*)>(.*?)</\\1>", Pattern.DOTALL).matcher(sqlContent);

        while (matcher.find()) {
            String tagName = matcher.group(1).toLowerCase();
            String attributesStr = matcher.group(2);
            String content = matcher.group(3);

            TagType type;
            try {
                type = TagType.valueOf(tagName.toUpperCase());
            } catch (IllegalArgumentException e) {
                continue; // 跳过未知标签
            }

            Map<String, String> attributes = parseAttributes(attributesStr);
            tags.add(new DynamicTagInfo(type, matcher.start(), matcher.end(), content, attributes));
        }
        return tags;
    }

    private static Map<String, String> parseAttributes(String attributesStr) {
        Map<String, String> attributes = new HashMap<>();
        Matcher matcher = Pattern.compile("(\\w+)\\s*=\\s*\"([^\"]*)\"").matcher(attributesStr);

        while (matcher.find()) {
            attributes.put(matcher.group(1), matcher.group(2));
        }
        return attributes;
    }

    // ==================== 工具方法 ====================

    private static boolean evaluateExpression(String expr, Map<String, Object> params) {
        // 简化实现，实际应使用OGNL或SpEL
        if (expr == null) return false;

        // 处理简单比较
        if (expr.contains("!=")) {
            String[] parts = expr.split("!=");
            String key = parts[0].trim();
            String value = parts[1].trim().replaceAll("['\"]", "");
            Object paramValue = params.get(key);
            return paramValue != null && !paramValue.toString().equals(value);
        }

        if (expr.contains("==")) {
            String[] parts = expr.split("==");
            String key = parts[0].trim();
            String value = parts[1].trim().replaceAll("['\"]", "");
            Object paramValue = params.get(key);
            return paramValue != null && paramValue.toString().equals(value);
        }

        // 处理null检查
        if (expr.endsWith("!= null")) {
            String key = expr.substring(0, expr.indexOf("!")).trim();
            return params.get(key) != null;
        }

        if (expr.endsWith("== null")) {
            String key = expr.substring(0, expr.indexOf("=")).trim();
            return params.get(key) == null;
        }

        // 处理存在性检查
        if (expr.endsWith("!= ''") || expr.endsWith("!= \"\"")) {
            String key = expr.substring(0, expr.indexOf("!")).trim();
            Object value = params.get(key);
            return value != null && !value.toString().isEmpty();
        }

        return false;
    }

    private static String sanitizeSqlValue(String value) {
        // 安全处理：防止SQL注入
        return value
                .replace(";", "")
                .replace("--", "")
                .replace("/*", "")
                .replace("*/", "");
    }


    /**
     * 从XML内容中提取SQL语句
     */
    public static String extractSqlContent(String xmlContent, String sqlId) {
        // 使用JDK原生XML解析，避免第三方依赖
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new InputSource(new StringReader(xmlContent)));

            NodeList sqlNodes = doc.getElementsByTagName("sql");
            for (int i = 0; i < sqlNodes.getLength(); i++) {
                Element sqlElement = (Element) sqlNodes.item(i);
                String idValue = sqlElement.getAttribute("id");
                if (sqlId.equals(idValue)) {
                    return sqlElement.getTextContent().trim();
                }
            }
        } catch (Exception e) {
            log.error("解析XML失败", e);
        }
        return "";
    }

}
